package algorithm

import (
	"fmt"
	"math"
	"math/rand"
	"sort"
	"time"

	"b2c-delivery-optimization/internal/model"
)

// WaveAllocationStrategy 波次分配策略
type WaveAllocationStrategy struct {
	MaxOrdersPerWave int     // 每个波次最大订单数
	PriorityWeight   float64 // 优先级权重
	LocationWeight   float64 // 位置权重
}

// NewWaveAllocationStrategy 创建新的波次分配策略
func NewWaveAllocationStrategy(maxOrdersPerWave int) *WaveAllocationStrategy {
	// 初始化随机数生成器
	rand.Seed(time.Now().UnixNano())

	return &WaveAllocationStrategy{
		MaxOrdersPerWave: maxOrdersPerWave,
		PriorityWeight:   0.7, // 优先级权重默认值
		LocationWeight:   0.3, // 位置权重默认值
	}
}

// OrderGroup 订单分组
type OrderGroup struct {
	Orders          []model.Order
	DeliveryStation string
	TotalPriority   float64
	OrderCount      int
	AveragePriority float64
	AvgLocation     model.Location
}

// OrderScore 订单得分
type OrderScore struct {
	Order model.Order
	Score float64
}

// AllocateOrders 分配订单到波次
func (s *WaveAllocationStrategy) AllocateOrders(orders []model.Order) ([]model.Wave, error) {
	if len(orders) == 0 {
		return nil, fmt.Errorf("订单列表为空")
	}
	//fmt.Printf("开始分配订单，总订单数: %d\n", len(orders))
	// 初始化指标
	metrics := &AlgorithmMetrics{
		Timestamp: time.Now(),
	}
	// 按配送站分组
	stationGroups := s.groupOrdersByDeliveryStation(orders)
	//fmt.Printf("订单已按配送站分组，共 %d 个组\n", len(stationGroups))
	// 处理每个配送站的订单组
	var waves []model.Wave
	for stationID, group := range stationGroups {
		//fmt.Printf("处理配送站 %s 的订单组，订单数: %d\n", stationID, len(group.Orders))
		stationWaves, err := s.processOrderGroup(group)
		if err != nil {
			return nil, fmt.Errorf("处理配送站 %s 的订单组失败: %v", stationID, err)
		}
		waves = append(waves, stationWaves...)
		//fmt.Printf("配送站 %s 生成了 %d 个波次\n", stationID, len(stationWaves))
		//for i, wave := range stationWaves {
		//	fmt.Printf("  波次 %d: %d 个订单\n", i+1, len(wave.Orders))
		//}
	}

	// 验证分配结果
	if len(waves) == 0 {
		return nil, fmt.Errorf("未能生成任何波次")
	}

	// 收集指标
	metrics.Timestamp = time.Now()
	metrics.PriorityScore = s.calculatePriorityScore(waves[0].Orders)
	metrics.LocationScore = s.calculateLocationScore(waves[0].Orders)
	metrics.BalanceScore = s.calculateBalanceScore(waves[0].Orders)

	//fmt.Printf("波次分配完成，共生成 %d 个波次\n", len(waves))
	return waves, nil
}

// groupOrdersByDeliveryStation 按配送站对订单分组
func (s *WaveAllocationStrategy) groupOrdersByDeliveryStation(orders []model.Order) map[string]OrderGroup {
	groups := make(map[string]OrderGroup)

	for _, order := range orders {
		group := groups[order.DeliveryStationID]
		group.Orders = append(group.Orders, order)
		group.TotalPriority += float64(order.Priority)
		group.OrderCount++
		groups[order.DeliveryStationID] = group
	}

	// 计算每个组的平均优先级和位置
	for stationID, group := range groups {
		if group.OrderCount > 0 {
			group.AveragePriority = group.TotalPriority / float64(group.OrderCount)
			groups[stationID] = group
		}
	}

	return groups
}

// processOrderGroup 处理单个订单组
func (s *WaveAllocationStrategy) processOrderGroup(group OrderGroup) ([]model.Wave, error) {
	if len(group.Orders) == 0 {
		return nil, fmt.Errorf("订单组为空")
	}
	// 计算订单得分
	scores := s.scoreOrders(group.Orders)
	//fmt.Printf("计算了 %d 个订单的得分\n", len(scores))
	// 按得分排序
	sort.Slice(scores, func(i, j int) bool {
		return scores[i].Score > scores[j].Score
	})
	// 分配订单到波次
	waves := s.distributeToWaves(scores)
	//fmt.Printf("将订单分配到 %d 个波次\n", len(waves))
	return waves, nil
}

// scoreOrders 对订单进行评分
func (s *WaveAllocationStrategy) scoreOrders(orders []model.Order) []OrderScore {
	scores := make([]OrderScore, len(orders))
	for i, order := range orders {
		priorityScore := float64(order.Priority) / 5.0 // 归一化优先级得分
		locationScore := 1.0                           // 位置得分初始为1.0
		scores[i] = OrderScore{
			Order: order,
			Score: s.PriorityWeight*priorityScore + s.LocationWeight*locationScore,
		}
	}
	return scores
}

// distributeToWaves 将订单分配到波次
func (s *WaveAllocationStrategy) distributeToWaves(scores []OrderScore) []model.Wave {
	var waves []model.Wave
	currentWave := model.Wave{
		ID:        fmt.Sprintf("W%s_%d_%d", time.Now().Format("20060102150405"), len(waves)+1, rand.Intn(1000000)),
		Orders:    make([]model.Order, 0),
		Status:    model.WaveStatusCreated,
		CreatedAt: time.Now(),
	}

	for _, score := range scores {
		if len(currentWave.Orders) >= s.MaxOrdersPerWave {
			waves = append(waves, currentWave)
			currentWave = model.Wave{
				ID:        fmt.Sprintf("W%s_%d_%d", time.Now().Format("20060102150405"), len(waves)+1, rand.Intn(1000000)),
				Orders:    make([]model.Order, 0),
				Status:    model.WaveStatusCreated,
				CreatedAt: time.Now(),
			}
		}
		currentWave.Orders = append(currentWave.Orders, score.Order)
	}

	if len(currentWave.Orders) > 0 {
		waves = append(waves, currentWave)
	}

	return waves
}

// updateAvgLocation 更新平均位置
func (s *WaveAllocationStrategy) updateAvgLocation(current, new model.Location, count int) model.Location {
	return model.Location{
		Latitude:  (current.Latitude*float64(count-1) + new.Latitude) / float64(count),
		Longitude: (current.Longitude*float64(count-1) + new.Longitude) / float64(count),
	}
}

// calculateNormalizedDistance 计算归一化距离
func (s *WaveAllocationStrategy) calculateNormalizedDistance(loc1, loc2 model.Location) float64 {
	dx := loc1.Longitude - loc2.Longitude
	dy := loc1.Latitude - loc2.Latitude
	distance := math.Sqrt(dx*dx + dy*dy)
	// 归一化到0-1范围
	return math.Min(distance/100.0, 1.0)
}

// calculatePriorityScore 计算优先级得分
func (s *WaveAllocationStrategy) calculatePriorityScore(wave []model.Order) float64 {
	if len(wave) == 0 {
		return 0.0
	}

	// 计算波次中订单的平均优先级
	totalPriority := 0
	for _, order := range wave {
		totalPriority += order.Priority
	}
	return float64(totalPriority) / float64(len(wave))
}

// calculateLocationScore 计算位置得分
func (s *WaveAllocationStrategy) calculateLocationScore(wave []model.Order) float64 {
	if len(wave) < 2 {
		return 1.0
	}

	// 计算波次中订单位置的平均距离
	totalDistance := 0.0
	count := 0
	for i := 0; i < len(wave); i++ {
		for j := i + 1; j < len(wave); j++ {
			totalDistance += s.calculateNormalizedDistance(wave[i].Location, wave[j].Location)
			count++
		}
	}

	if count == 0 {
		return 1.0
	}
	return 1.0 - (totalDistance / float64(count))
}

// calculateBalanceScore 计算平衡得分
func (s *WaveAllocationStrategy) calculateBalanceScore(wave []model.Order) float64 {
	if len(wave) == 0 {
		return 0.0
	}

	// 计算波次中订单数量的平衡度
	expectedCount := float64(s.MaxOrdersPerWave)
	actualCount := float64(len(wave))
	return 1.0 - math.Abs(actualCount-expectedCount)/expectedCount
}
